package com.sun.gis.jstdt;

import com.sun.gis.tools.jstdt.TileDownloader;
import org.junit.Test;
import org.springframework.boot.test.context.SpringBootTest;

import java.io.File;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import java.util.concurrent.TimeUnit;

// 使用多线程下载，将切片下载均摊到每个线程
@SpringBootTest
public class DownloaderTest1 {

    private static final int THREAD_COUNT = 10;  // 线程池的线程数量

    @Test
    public void test() {
//        String baseUrl = "https://jiangsu.tianditu.gov.cn/historyraster/rest/services/History/yxdt_js_1966_2k/MapServer/tile/";
//        String outputDir = "F:\\data\\jiangsu\\1966";

//        String baseUrl = "https://jiangsu.tianditu.gov.cn/historyraster/rest/services/History/yxdt_js_1976_2k/MapServer/tile/";
//        String outputDir = "F:\\data\\jiangsu\\1976";

        String baseUrl = "https://jiangsu.tianditu.gov.cn/mapjs2/rest/services/MapJS/js_yxdt_latest/MapServer/tile/";
        String outputDir = "F:\\data\\jiangsu\\2023";



        File directory = new File(outputDir);
        if (!directory.exists()) {
            directory.mkdirs();
        }

        double[] fullExtent = {-180, -90, 180, 90};
        double[] realExtent = {116.10358013377254, 30.710719079012677, 122.09030402444137, 35.21265930204362};
        double width4490 = fullExtent[2] - fullExtent[0];
        double height4490 = fullExtent[3] - fullExtent[1];

        int tileWidth = 256;
        int tileHeight = 256;

        double[] resolutions4490 = new double[19];
        int maxZoom = 18;

        for (int z = 1; z <= maxZoom; z++) {
            resolutions4490[z] = width4490 / (tileWidth * Math.pow(2, z));
        }

        ExecutorService executorService = Executors.newFixedThreadPool(THREAD_COUNT);
        List<Runnable> tasks = new ArrayList<>();

        try {
            for (int z = 7; z <= maxZoom; z++) {
                int numCols = (int) Math.ceil(width4490 / (resolutions4490[z] * tileWidth));
                int numRows = (int) Math.ceil(height4490 / (resolutions4490[z] * tileHeight));

                for (int y = 0; y < numRows; y++) {
                    for (int x = 0; x < numCols; x++) {
                        double tileMinX = -180 + x * resolutions4490[z] * tileWidth;
                        double tileMaxX = tileMinX + resolutions4490[z] * tileWidth;
                        double tileMaxY = 90 - y * resolutions4490[z] * tileHeight;
                        double tileMinY = tileMaxY - resolutions4490[z] * tileHeight;
                        if (tileMinX < realExtent[2] && tileMaxX > realExtent[0] && tileMinY < realExtent[3] && tileMaxY > realExtent[1]) {
                            tasks.add(new TileDownloadTask(z, x, y, numCols, baseUrl, outputDir, resolutions4490, tileWidth, tileHeight, realExtent));
                        }
                    }
                }
            }

            // Distribute tasks to threads
            int totalTasks = tasks.size();
            int perThread = totalTasks / THREAD_COUNT;
            int remainingTasks = totalTasks % THREAD_COUNT;
            int start = 0;

            for (int i = 0; i < THREAD_COUNT; i++) {
                int end = start + perThread + (i < remainingTasks ? 1 : 0);
                List<Runnable> threadTasks = tasks.subList(start, end);
                executorService.execute(() -> {
                    for (Runnable task : threadTasks) {
                        task.run();
                    }
                });
                start = end;
            }

            executorService.shutdown();
            executorService.awaitTermination(30, TimeUnit.DAYS);
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

    private static class TileDownloadTask implements Runnable {
        private int zoomLevel;
        private int x;
        private int y;
        private int numCols;
        private String baseUrl;
        private String outputDir;
        private double[] resolutions;
        private int tileWidth;
        private int tileHeight;
        private double[] realExtent;

        public TileDownloadTask(int zoomLevel, int x, int y, int numCols, String baseUrl, String outputDir, double[] resolutions, int tileWidth, int tileHeight, double[] realExtent) {
            this.zoomLevel = zoomLevel;
            this.x = x;
            this.y = y;
            this.numCols = numCols;
            this.baseUrl = baseUrl;
            this.outputDir = outputDir;
            this.resolutions = resolutions;
            this.tileWidth = tileWidth;
            this.tileHeight = tileHeight;
            this.realExtent = realExtent;
        }

        @Override
        public void run() {
            String outputFilePath = outputDir + File.separator + "tile_" + zoomLevel + "_" + y + "_" + x + ".png";
            File tileFile = new File(outputFilePath);
            if (!tileFile.exists()) {
                String tileUrl = baseUrl + zoomLevel + "/" + y + "/" + x;
                try {
                    TileDownloader.downloadTile(tileUrl, outputFilePath);
                    System.out.println("Successfully downloaded: " + outputFilePath);
                } catch (Exception e) {
                    System.err.println("Failed to download tile " + zoomLevel + "/" + y + "/" + x + ": " + e.getMessage());
                }
            }
        }
    }
}
